import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.AbstractAction;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;

import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Color;
import java.awt.Font;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Random;

/**
 * Visual Component of the MULE game. The GameScreen is constructed in a way
 * that incorporates multiple layers. For each layer, there are various methods
 * that controls what occurs. The graphical interface incorporate Java Swing to
 * deal with property selection and other methods that the player interacts with
 * the game and game board. The main purpose of this code is to house the game
 * board. The game board has two primary screens, which are also encompassed in
 * this class.
 * 
 * @author GT Five-O
 * @version v1.0b
 * 
 */
public class GameScreen extends JFrame implements java.io.Serializable {

    private static final long serialVersionUID = 1L;
    private JLayeredPane mainPane;
    private JLayeredPane storePane;

    private JPanel infoPane;
    private JPanel sidebar;
    private JPanel cardPanel;

    private LinkedList<IDAssociator> ownedPropertiesJLabels = new LinkedList<IDAssociator>();
    private LinkedList<IDAssociator> ownedMuleJLabels = new LinkedList<IDAssociator>();

    private JLabel message;
    private JLabel roundNum;
    private JLabel storeInventory;
    public JLabel timer;
    private JLabel screenCover = new JLabel("Please wait...");;

    private JButton ok;
    private JButton[] storeButtons = new JButton[7];

    private String storeText;

    private boolean covered = false;
    private boolean selected = false;
    private boolean mPlaced = false;
    private boolean vPlace = false;
    private boolean passedEnter = false;
    private boolean pressed = false;
    private boolean pubClicked = true;
    private static boolean allowed = false;
    private static boolean grantPhase = true;
    private static boolean landPhase = false;
    private static boolean mulePhase = false;
    private static boolean proceed = true;
    private static boolean sellPhase = false;

    private Player[] allPlayerInfo;
    private Player user;

    private ArrayList<String> chosen = new ArrayList<String>();
    private CardLayout cards;
    private LandOffice landStore;
    private Pub pub;
    private Random rand = new Random();
    private Store store;
    private Property lastClickedProperty;
    private static boolean next = true;

    /*
     * JLabels for User Information
     * 
     * [] Name [] Money [][] Details - [] Race - [] Color - [] Mules - [] Food -
     * [] Energy - [] SmithOre
     */
    private JLabel[] userNames;
    private JLabel[] userMoney;
    private JLabel[][] userDetails;

    /**
     * constructor for creating the game screen based on the number of players
     * The buttons for each of the land types is created as well as the bottom
     * and side panels which contain player and store data
     * 
     * @param players
     *            - the array of players
     */
    public GameScreen(Player[] players, String map) {

        this.allPlayerInfo = players;
        store = new Store(this);

        userNames = new JLabel[players.length];
        userMoney = new JLabel[players.length];
        userDetails = new JLabel[players.length][6];

        setAlwaysOnTop(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 0, 0);
        setSize(1225, 704);
        setResizable(false);
        mainPane = new JLayeredPane();

        JLabel boardLabel = new JLabel("");
        System.out.println("The map selected is: " + map);
        boardLabel.setIcon(new ImageIcon("Images/" + map));
        boardLabel.setOpaque(true);
        boardLabel.setBounds(0, 0, GameConstants.DEFAULT_WIDTH,
                GameConstants.DEFAULT_HEIGHT);
        mainPane.add(boardLabel, JLayeredPane.PALETTE_LAYER);
        mainPane.setFocusable(true);
        mainPane.addKeyListener(new EnterListener());
        mainPane.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "doPassed");
        mainPane.getActionMap().put("doPassed", new EnterAction());

        LandButton[][] button = new LandButton[5][9];
        int width = 113;
        int height = 115;

        /*
         * Game Map Creation
         */

        if(map.equals("Bikini Bottom")){
            for (int y = 0; y < 5; y++) {
                for (int x = 0; x < 9; x++) {
                    button[y][x] = new LandButton("");
                    button[y][x]
                            .setBounds((width * x), (height * y), width, height);
                    mainPane.add(button[y][x], JLayeredPane.DEFAULT_LAYER);
                    String location = y + "," + x;
                    button[y][x].addActionListener(new ButtonListener(location,
                            (width * x), (height * y), width, height));
                    button[y][x].setOpaque(false);
                    button[y][x].setContentAreaFilled(false);
                    button[y][x].setBorderPainted(false);
                    if ((x == 1 && y == 1) || (x == 2 && y == 0)
                            || (x == 8 && y == 2)) {
                        button[y][x].setText("m3");
                        button[y][x].setProperty(new Mountain3());

                    } else if ((x == 1 && y == 3) || (x == 2 && y == 4)
                            || (x == 8 && y == 4) || (x == 6 && y == 3)) {
                        button[y][x].setText("m1");
                        button[y][x].setProperty(new Mountain1());
                    } else if ((x == 0 && y == 2) || (x == 6 && y == 0)
                            || (x == 8 && y == 1)) {
                        button[y][x].setText("m1");
                        button[y][x].setProperty(new Mountain2());
                    } else {
                        button[y][x].setText("River at " + location);
                        button[y][x].setProperty(new River());
                    } 
                    button[y][x].getProperty().setLocation(location);
                }
            }
        } else {
            for (int y = 0; y < 5; y++) {
                for (int x = 0; x < 9; x++) {
                    button[y][x] = new LandButton("");
                    button[y][x]
                            .setBounds((width * x), (height * y), width, height);
                    mainPane.add(button[y][x], JLayeredPane.DEFAULT_LAYER);
                    String location = y + "," + x;
                    button[y][x].addActionListener(new ButtonListener(location,
                            (width * x), (height * y), width, height));
                    button[y][x].setOpaque(false);
                    button[y][x].setContentAreaFilled(false);
                    button[y][x].setBorderPainted(false);
                    if ((x == 1 && y == 1) || (x == 2 && y == 0)
                            || (x == 8 && y == 2)) {
                        button[y][x].setText("m1");
                        button[y][x].setProperty(new Mountain1());

                    } else if ((x == 1 && y == 3) || (x == 2 && y == 4)
                            || (x == 8 && y == 4) || (x == 6 && y == 3)) {
                        button[y][x].setText("m2");
                        button[y][x].setProperty(new Mountain2());
                    } else if ((x == 0 && y == 2) || (x == 6 && y == 0)
                            || (x == 8 && y == 1)) {
                        button[y][x].setText("m3");
                        button[y][x].setProperty(new Mountain3());
                    } else if (x == 4) {
                        button[y][x].setText("River at " + location);
                        button[y][x].setProperty(new River());
                    } else {
                        button[y][x].setText("plains");
                        button[y][x].setProperty(new Plain());
                    }
                    button[y][x].getProperty().setLocation(location);
                }
            }
        }
        /*
         * Store Panel
         */
        storePane = new JLayeredPane();

        JLabel container = new JLabel("");
        container.setIcon(new ImageIcon("Images/store.jpg"));
        container.setOpaque(true);
        container.setBounds(0, 0, GameConstants.DEFAULT_WIDTH,
                GameConstants.DEFAULT_HEIGHT-14);
        storePane.add(container, JLayeredPane.PALETTE_LAYER);

        /*
         * Land Office Button
         */
        storeButtons[0] = new JButton("");
        storeButtons[0].setBounds(19, 0, 320, 250);
        storePane.add(storeButtons[0], JLayeredPane.DEFAULT_LAYER);
        storeButtons[0].addActionListener(new townButtonListener("LandOffice",
                19, 0, 320, 250));
        storeButtons[0].setOpaque(false);
        storeButtons[0].setContentAreaFilled(false);
        storeButtons[0].setBorderPainted(false);

        /*
         * Pub Button
         */
        storeButtons[1] = new JButton("");
        storeButtons[1].setBounds(350, 0, 320, 250);
        storePane.add(storeButtons[1], JLayeredPane.DEFAULT_LAYER);
        storeButtons[1].addActionListener(new townButtonListener("Pub", 350, 0,
                320, 250));
        storeButtons[1].setOpaque(false);
        storeButtons[1].setContentAreaFilled(false);
        storeButtons[1].setBorderPainted(false);

        /*
         * Mule Button
         */
        storeButtons[2] = new JButton("");
        storeButtons[2].setBounds(681, 0, 320, 250);
        storePane.add(storeButtons[2], JLayeredPane.DEFAULT_LAYER);
        storeButtons[2].addActionListener(new townButtonListener("MULEStore",
                681, 0, 320, 250));
        storeButtons[2].setOpaque(false);
        storeButtons[2].setContentAreaFilled(false);
        storeButtons[2].setBorderPainted(false);

        /*
         * Food Button
         */
        storeButtons[3] = new JButton("");
        storeButtons[3].setBounds(19, 341, 320, 250);
        storePane.add(storeButtons[3], JLayeredPane.DEFAULT_LAYER);
        storeButtons[3].addActionListener(new townButtonListener("FoodStore",
                19, 341, 320, 250));
        storeButtons[3].setOpaque(false);
        storeButtons[3].setContentAreaFilled(false);
        storeButtons[3].setBorderPainted(false);

        /*
         * Energy Button
         */
        storeButtons[4] = new JButton("");
        storeButtons[4].setBounds(350, 341, 320, 250);
        storePane.add(storeButtons[4], JLayeredPane.DEFAULT_LAYER);
        storeButtons[4].addActionListener(new townButtonListener("EnergyStore",
                350, 341, 320, 250));
        storeButtons[4].setOpaque(false);
        storeButtons[4].setContentAreaFilled(false);
        storeButtons[4].setBorderPainted(false);

        /*
         * Ore Button
         */
        storeButtons[5] = new JButton("");
        storeButtons[5].setBounds(681, 341, 320, 250);
        storePane.add(storeButtons[5], JLayeredPane.DEFAULT_LAYER);
        storeButtons[5].addActionListener(new townButtonListener("SmithStore",
                681, 341, 320, 250));
        storeButtons[5].setOpaque(false);
        storeButtons[5].setContentAreaFilled(false);
        storeButtons[5].setBorderPainted(false);

        /*
         * 'Back to Map' Button
         */
        storeButtons[6] = new JButton("Return to Map");
        storeButtons[6].setBounds(412, 267, 200, 30);
        storePane.add(storeButtons[6], JLayeredPane.POPUP_LAYER);
        storeButtons[6].addActionListener(new HomeListen());
        storeButtons[6].setOpaque(true);
        storeButtons[6].setContentAreaFilled(true);
        storeButtons[6].setBorderPainted(false);
        storeButtons[6].setBackground(Color.yellow);
        storeButtons[6].setForeground(Color.black);
        storeButtons[6].setFont(new Font(GameConstants.FONT, Font.BOLD, 11));

        /*
         * Card Layout Construction
         */
        cardPanel = new JPanel(new CardLayout());
        cardPanel.add(mainPane, "Main Game Screen");
        cardPanel.add(storePane, "Store Screen");
        setContentPane(cardPanel);

        cards = (CardLayout) (cardPanel.getLayout());
        landStore = new LandOffice(this);
        pub = new Pub();

        /*
         * Lower Info Panel
         */
        generateInfoPanel();

        /*
         * Right Side Info Panel
         */
        sidebar = new BackgroundPanel("sidebar.png");
        sidebar.setBounds(GameConstants.DEFAULT_WIDTH, 0, 200, 704);
        sidebar.setBackground(Color.WHITE);
        mainPane.add(sidebar, JLayeredPane.DRAG_LAYER);
        sidebar.setLayout(null);

        /*
         * Store Inventory Information
         */
        storeInventory = new JLabel("");
        storeText = "Food: " + store.getFood() + "<br>Energy: "
                + store.getEnergy() + "<br>Ore: " + store.getOre()
                + "<br>Mules: " + store.getMule();
        storeInventory.setText("<html>" + storeText + "</html>");
        storeInventory.setForeground(Color.DARK_GRAY);
        storeInventory.setFont(new Font(GameConstants.FONT, Font.BOLD, 11));
        storeInventory.setVerticalAlignment(SwingConstants.TOP);
        storeInventory.setHorizontalAlignment(SwingConstants.LEFT);
        storeInventory.setBounds(19, 275, 163, 147);
        sidebar.add(storeInventory);

        /*
         * Message Box
         */
        message = new JLabel("");
        message.setText("<html>Welcome to the MULE game!</html>");
        message.setForeground(Color.DARK_GRAY);
        message.setFont(new Font(GameConstants.FONT, Font.BOLD, 11));
        message.setVerticalAlignment(SwingConstants.TOP);
        message.setHorizontalAlignment(SwingConstants.LEFT);
        message.setBounds(19, 59, 163, 147);
        sidebar.add(message);

        roundNum = new JLabel("");
        roundNum.setForeground(Color.LIGHT_GRAY);
        roundNum.setHorizontalAlignment(SwingConstants.CENTER);
        roundNum.setFont(new Font(GameConstants.FONT, Font.BOLD, 99));
        roundNum.setBounds(32, 410, 139, 97);
        sidebar.add(roundNum);

        /*
         * Timer Display
         */
        timer = new JLabel("N/A");
        timer.setForeground(Color.LIGHT_GRAY);
        timer.setHorizontalAlignment(SwingConstants.CENTER);
        timer.setFont(new Font(GameConstants.FONT, Font.BOLD, 99));
        timer.setBounds(32, 565, 139, 97);
        sidebar.add(timer);

    }

    /**
     * sets the cover text for the screen while creating buttons that allow the
     * user to interact with the game
     * 
     * @param text
     */
    public void customDialogue(String text) {
        this.setGameScreenCoverText(text);
        this.coverGameScreen();
        this.addOkButton();
        while (!pressed) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * alerts the user that he/she doesn't have enough money
     */
    private void notEnoughMoneyMessage() {
        message.setText("<html>Sorry! You don't have enough money to purchase this item.</html>");
    }

    /**
     * alerts the user that the purchase was successful
     */
    private void purchaseSuccess(String playerName, String itemName) {
        message.setText("<html>Player " + playerName
                + " successfully purchased a " + itemName + " item.</html>");
    }

    /**
     * alerts the user of an item unavailability
     */
    private void itemNotAvailable(String item) {
        message.setText("<html>There is no " + item + " item available.</html>");
    }

    /**
     * adds an "OK" butten to the mainPane
     */
    public void addOkButton() {
        ok = new JButton("Gotcha!");
        ok.setBounds(0, 0, 117, 29);
        ok.setOpaque(true);
        ok.addActionListener(new okButtonListener());
        mainPane.add(ok, JLayeredPane.DRAG_LAYER);
    }

    /**
     * creates a cover for the game screen
     */
    public void coverGameScreen() {
        covered = true;
        screenCover.setFont(new Font(GameConstants.FONT, Font.BOLD, 18));
        screenCover.setHorizontalAlignment(SwingConstants.CENTER);
        screenCover.setBackground(Color.white);
        screenCover.setBounds(0, 0, GameConstants.DEFAULT_WIDTH,
                GameConstants.DEFAULT_HEIGHT-14);
        screenCover.setOpaque(true);
        Component visible = this.getComponent(0);
        ((JRootPane) visible).add(screenCover, JLayeredPane.POPUP_LAYER);
        setAllowed(false);
        setlandPhase(false);
        landStore.endThread();
    }

    /**
     * makes the game screen appear and repaints
     */
    public void uncoverGameScreen() {
        covered = false;
        JRootPane visible = (JRootPane) this.getComponent(0);
        visible.remove(screenCover);
        mainPane.revalidate();
        mainPane.repaint();
        storePane.revalidate();
        storePane.repaint();
    }

    /**
     * sets the text that is placed on the cover
     * 
     * @param text
     * 
     */
    public void setGameScreenCoverText(String text) {
        screenCover.setText(text);
    }

    /**
     * creates the bottom pane based on the player's info
     */
    private void generateInfoPanel() {

        infoPane = new BackgroundPanel("infobar.png");
        infoPane.setBounds(0, 580, GameConstants.DEFAULT_WIDTH, 110);
        infoPane.setBackground(new Color(20, 121, 143));
        mainPane.add(infoPane, JLayeredPane.POPUP_LAYER);
        infoPane.setLayout(null);

        int xUnit = 17;
        int width = 113;
        int height = 14;

        for (int i = 0; i < allPlayerInfo.length; i++) {

            /* Player name */
            userNames[i] = new JLabel(allPlayerInfo[i].getPlayerName());
            userNames[i].setFont(new Font(GameConstants.FONT, Font.BOLD, 13));
            userNames[i].setForeground(Color.WHITE);
            userNames[i].setBounds(xUnit, 16, width, height);
            infoPane.add(userNames[i]);

            /* Player race (0) */
            userDetails[i][0] = new JLabel("Race: "
                    + allPlayerInfo[i].getPlayerRace());
            userDetails[i][0].setFont(new Font(GameConstants.FONT, Font.PLAIN,
                    11));
            userDetails[i][0].setForeground(Color.WHITE);
            userDetails[i][0].setBounds(xUnit, 37, width, height);
            infoPane.add(userDetails[i][0]);

            /* Player color (1) */
            userDetails[i][1] = new JLabel("Color: "
                    + allPlayerInfo[i].getPlayerColor());
            userDetails[i][1].setFont(new Font(GameConstants.FONT, Font.PLAIN,
                    11));
            userDetails[i][1].setForeground(Color.WHITE);
            userDetails[i][1].setBounds(xUnit, 54, width, height);
            infoPane.add(userDetails[i][1]);

            /* Player money */
            userMoney[i] = new JLabel("Money: $" + allPlayerInfo[i].getMoney());
            userMoney[i].setFont(new Font(GameConstants.FONT, Font.PLAIN, 11));
            userMoney[i].setForeground(Color.WHITE);
            userMoney[i].setBounds(xUnit, 72, width, height);
            infoPane.add(userMoney[i]);

            xUnit = xUnit + 100;

            /* Player mules (2) */
            userDetails[i][2] = new JLabel("Mules: " + "N/A");
            userDetails[i][2].setFont(new Font(GameConstants.FONT, Font.PLAIN,
                    11));
            userDetails[i][2].setForeground(Color.WHITE);
            userDetails[i][2].setBounds(xUnit, 19, width, height);
            infoPane.add(userDetails[i][2]);

            /* Player food (3) */
            userDetails[i][3] = new JLabel("Food: "
                    + allPlayerInfo[i].getFood());
            userDetails[i][3].setFont(new Font(GameConstants.FONT, Font.PLAIN,
                    11));
            userDetails[i][3].setForeground(Color.WHITE);
            userDetails[i][3].setBounds(xUnit, 37, width, height);
            infoPane.add(userDetails[i][3]);

            /* Player energy (4) */
            userDetails[i][4] = new JLabel("Energy: "
                    + allPlayerInfo[i].getEnergy());
            userDetails[i][4].setFont(new Font(GameConstants.FONT, Font.PLAIN,
                    11));
            userDetails[i][4].setForeground(Color.WHITE);
            userDetails[i][4].setBounds(xUnit, 54, width, height);
            infoPane.add(userDetails[i][4]);

            /* Player smithore (5) */
            userDetails[i][5] = new JLabel("Smithore: "
                    + allPlayerInfo[i].getOre());
            userDetails[i][5].setFont(new Font(GameConstants.FONT, Font.PLAIN,
                    11));
            userDetails[i][5].setForeground(Color.WHITE);
            userDetails[i][5].setBounds(xUnit, 72, width, height);
            infoPane.add(userDetails[i][5]);

            xUnit = xUnit + 115;
        }

    }

    /**
     * Method used to constant update the bottom panel and the side panels.
     */
    public void updateInfoPanel() {

        for (int i = 0; i < allPlayerInfo.length; i++) {
            userMoney[i].setText("Money: $" + allPlayerInfo[i].getMoney());
            userDetails[i][2].setText("Mules: "
                    + allPlayerInfo[i].getMuleCount());
            userDetails[i][3].setText("Food: " + allPlayerInfo[i].getFood());
            userDetails[i][4]
                    .setText("Energy: " + allPlayerInfo[i].getEnergy());
            userDetails[i][5].setText("Smithore: " + allPlayerInfo[i].getOre());
        }

        storeText = "Food: " + store.getFood() + "<br>Energy: "
                + store.getEnergy() + "<br>Ore: " + store.getOre()
                + "<br>Mules: " + store.getMule();
        storeInventory.setText("<html>" + storeText + "</html>");

    }

    /**
     * Sets the land color based on the player's color choice when the land is
     * bought. OwnedProperties associates each icon with a specific land.
     * 
     * @param color
     */
    public void setLandColor(String color) {
        if (color.equals("Red")) {
            ownedPropertiesJLabels.getLast().setJLabelIcon(
                    "Images/PlayerColorIcons/red.png");
        } else if (color.equals("Black")) {
            ownedPropertiesJLabels.getLast().setJLabelIcon(
                    "Images/PlayerColorIcons/black.png");
        } else if (color.equals("Green")) {
            ownedPropertiesJLabels.getLast().setJLabelIcon(
                    "Images/PlayerColorIcons/green.png");
        } else {
            ownedPropertiesJLabels.getLast().setJLabelIcon(
                    "Images/PlayerColorIcons/yellow.png");
        }
    }

    /**
     * Creates and icon for the mule based on its type ownedMuleJLables
     * associates the mule with the specific land.
     * 
     * @param s
     *            the type of mule being created
     */
    public void setMuleType(String s) {
        if (s.equals("Food")) {
            ownedMuleJLabels.getLast().setJLabelIcon(
                    "Images/MuleIcons/food.png");
        } else if (s.equals("Energy")) {
            ownedMuleJLabels.getLast().setJLabelIcon(
                    "Images/MuleIcons/energy.png");
        } else {
            ownedMuleJLabels.getLast()
            .setJLabelIcon("Images/MuleIcons/ore.png");
        }
    }

    /**
     * Returns the number of properties left to choose from.
     * 
     * @return Number of properties left to choose from.
     */
    public int openProp() {
        return GameConstants.TOTAL_PROPERTIES - chosen.size();
    }

    /**
     * Returns if a land is selected.
     * 
     * @return
     */
    public boolean landSelected() {
        return selected;
    }

    /**
     * Returns whether or not the mule has been placed.
     * 
     * @return the Mule that was placed.
     */
    public boolean mulePlaced() {
        return mPlaced;
    }

    /**
     * Setter for whether or not the mule has been placed.
     * 
     * @param input
     */
    public void setMPlaced(boolean input) {
        mPlaced = input;
    }

    /**
     * Checks if a mule is able to be placed on a specific land.
     * 
     * @return true if valid mule placed
     */
    public boolean validMulePlacement() {
        return vPlace;
    }

    /**
     * setter for the boolean checking if a mule can be placed on a specific
     * land
     * 
     * @param input
     */
    public void setVPlace(boolean input) {
        vPlace = input;
    }

    /**
     * setter for the land selected.
     * 
     * @param input
     */
    public void setSelected(boolean input) {
        selected = input;
    }

    /**
     * boolean that returns if the user passed on their turn
     * 
     * @return if user passed turn
     */
    public boolean passed() {
        return passedEnter;
    }

    /**
     * setter for whether the user passed their turn
     * 
     * @param input
     */
    public void setPassed(boolean input) {
        passedEnter = input;
    }

    /**
     * focuses pane so that the mainpane is displayed
     */
    public void focusPane() {
        mainPane.requestFocusInWindow();
    }

    /**
     * setter for the current player
     * 
     * @param p
     */
    public void setCurrent(Player p) {
        user = p;
    }

    /**
     * getter for the current player
     * 
     * @return
     */
    public Player getCurrent() {
        return user;
    }

    /**
     * setter method for when the player is allowed to buy land or not
     * 
     * @param b
     */
    public void setAllowed(boolean b) {
        allowed = b;
    }

    /**
     * returns true when the player is allowed to buy land, else false
     * 
     * @return
     */
    public boolean getGrant() {
        return grantPhase;
    }

    /**
     * sets the message that is seen by the user on the game screen
     * 
     * @param message
     */
    public void setMessage(String message) {
        this.message.setText(message);
    }

    /**
     * setter for the timer for when it is a certain player's turn
     * 
     * @param time
     */
    public void setTimer(String time) {
        this.timer.setText(time);
    }

    /**
     * setter for whether the user gets a grant to buy a plot of land
     * 
     * @param b
     */
    public void setGrant(boolean b) {
        grantPhase = b;
    }

    /**
     * this method adds the bottom and side bars seen when the game is being
     * played. Gives the user information about their current messages, their
     * resources available, time left, the current turn, and money left.
     * 
     */
    public void nextCard() {
        cards.next(cardPanel);
        if (next) {
            storePane.add(infoPane, JLayeredPane.POPUP_LAYER);
            storePane.add(sidebar, JLayeredPane.POPUP_LAYER);
            next = false;
        } else {
            mainPane.add(infoPane, JLayeredPane.POPUP_LAYER);
            mainPane.add(sidebar, JLayeredPane.POPUP_LAYER);
            next = true;
        }
    }

    /**
     * getter for the land phase
     * 
     * @return
     */
    public boolean getlandPhase() {
        return landPhase;
    }

    /**
     * setter for the land phase
     * 
     * @param b
     */
    public void setlandPhase(boolean b) {
        landPhase = b;
    }

    /**
     * getter the the mulePhase
     * 
     * @return
     */
    public boolean getMulePhase() {
        return mulePhase;
    }

    /**
     * setter for the mule phase boolean
     * 
     * @param b
     */
    public void setMulePhase(boolean b) {
        mulePhase = b;
    }

    /*
     * ActionListener for MAINPANE BUTTONS
     */
    private class ButtonListener implements ActionListener {

        private String location;
        private int x;
        private int y;
        private int width;
        private int height;

        /**
         * action listener constructor for buttons used in the game screen.
         * 
         * @param location
         * @param x
         * @param y
         * @param width
         * @param height
         */
        public ButtonListener(String location, int x, int y, int width,
                int height) {
            this.location = location;
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }

        /**
         * Listener for the action performed when a game tile is pressed on the
         * board.
         * 
         * @param e
         *            - random action event
         */
        public void actionPerformed(ActionEvent e) {
            proceed = true;
            mPlaced = false;
            vPlace = false;

            /* Don't save the property if the town button is clicked. */
            if (!this.location.equals("2,4")) {
                lastClickedProperty = ((LandButton) e.getSource())
                        .getProperty();
            }
            if (covered) {
                /* Town Button Clicked during Land Grant Phase */
            } else if (this.location.equals("2,4") && grantPhase) {
                JOptionPane.showMessageDialog(mainPane,
                        "Cannot Select the Town! Pick another tile!");
                focusPane();

                /* Town Button Clicked while buying land */
            } else if (this.location.equals("2,4") && landPhase) {
                JOptionPane.showMessageDialog(mainPane, "Going back to Town");
                landStore.endThread();
                focusPane();
                nextCard();
                allowed = false;

                /* TOWN Button Clicked */
            } else if (this.location.equals("2,4")) {
                storePane.add(infoPane, JLayeredPane.POPUP_LAYER);
                nextCard();

                /* Mule Placement Phase and no property at the specific location */
            } else if (!chosen.contains(location) && mulePhase) {
                JOptionPane.showMessageDialog(mainPane,
                        "Oops looks you dont have a property there!");
                store.setMuleSelection(true);
                proceed = false;
                mPlaced = false;

                /*
                 * Mule Placement Phase and Player doesn't own that specific
                 * property
                 */
            } else if (chosen.contains(location) && mulePhase
                    && !getCurrent().hasProp(location)) {
                JOptionPane.showMessageDialog(mainPane,
                        "Oops looks you dont have a property there!");
                store.setMuleSelection(true);
                proceed = false;
                mPlaced = false;
                vPlace = false;

                /* Mule Placement Phase and Player has that property */
            } else if (chosen.contains(location) && mulePhase
                    && getCurrent().hasProp(location)) {
                proceed = true;
                vPlace = true;
                ownedMuleJLabels
                .add(new IDAssociator(lastClickedProperty
                        .getPropertyID(), x + 5, y + 15, 50, 50,
                        mainPane, true));
                mPlaced = true;
                allowed = false;
                mulePhase = false;
                store.setMuleSelection(false);

                /* selling phase and the player DOES NOT have the property */
            } else if (sellPhase && !getCurrent().hasProp(location)) {
                selected = false;
                landStore.endThread();
                JOptionPane.showMessageDialog(mainPane,
                        "Oops looks you dont have a property there!");

                /* selling phase and the player has the property */
            } else if (sellPhase && getCurrent().hasProp(location)) {
                for (IDAssociator i : ownedPropertiesJLabels) {
                    if (i.getID() == lastClickedProperty.getPropertyID()) {
                        i.removeData();
                    }
                }
                for (IDAssociator i : ownedMuleJLabels) {
                    if (i.getID() == lastClickedProperty.getPropertyID()) {
                        i.removeData();
                    }
                }
                chosen.remove(location);
                selected = true;

                getCurrent().removeMule(
                        ((LandButton) e.getSource()).getProperty().getMule());
                lastClickedProperty = ((LandButton) e.getSource())
                        .getProperty();
                lastClickedProperty.removeMule();
                updateInfoPanel();
                sellPhase = false;
                /*
                 * This restriction is placed if the player is not allowed to
                 * interact with properties
                 */
            } else if (!allowed) {
                /*
                 * Player tries to chose a property that has already been
                 * selected by someone else
                 */
            } else if (chosen.contains(location)) {
                JOptionPane
                .showMessageDialog(mainPane,
                        "Oops looks you chose a property someone else owns! Pick Another!");
                /* If a valid property is clicked during land purchase */
            } else {
                chosen.add(location);
                getCurrent()
                .addProp(((LandButton) e.getSource()).getProperty());
                selected = true;

                /* store in linked list */
                ownedPropertiesJLabels.add(new IDAssociator(lastClickedProperty
                        .getPropertyID(), x + 57, y + 15, 50, 50, mainPane,
                        false));

                allowed = false;
            }
            updateInfoPanel();
        }
    }

    /**
     * Button Listener for ok button.
     * 
     */
    private class okButtonListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            pressed = true;
            uncoverGameScreen();
        }

    }

    /*
     * ActionListener for TOWN BUTTONS
     */
    private class townButtonListener implements ActionListener {

        private String location;
        private int x;
        private int y;
        private int width;
        private int height;

        public townButtonListener(String location, int x, int y, int width,
                int height) {
            this.location = location;
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }

        @Override
        /**
         * This method sets appropriate values to different elements based on what the user selects in the store. 
         * If the user selects Land office, a worker is created, the user can sell their land. If pub is clicked, the user
         * gets the appropriate money bonus and time gets updated. If food store is selected, the user can buy or sell their land
         * during their turn. Finally, if the user selects the SmithStore, the user can buy or sell their smithore.
         */
        public void actionPerformed(ActionEvent e) {
            /* store swing worker */
            SwingWorker sworker = new SwingWorker() {
                @Override
                protected Object doInBackground() throws Exception {
                    landStore.sellFunction();
                    return null;
                }
            };
            /* mule swing worker */
            SwingWorker mworker = new SwingWorker() {
                @Override
                protected Object doInBackground() throws Exception {
                    store.muleSelection();
                    return null;
                }

            };

            if (covered) {
                System.out.println("Screen covered.");
            } else if (location.equals("LandOffice")) {
                Object[] options = { "Sell", "Buy" };
                int n = JOptionPane
                        .showOptionDialog(storePane,
                                "Would like to buy or sell?", "LandOffice",
                                JOptionPane.YES_NO_CANCEL_OPTION,
                                JOptionPane.QUESTION_MESSAGE, null, options,
                                options[1]);

                /* LandStore sells land */
                if (n == 1) {
                    setlandPhase(true);
                    mainPane.add(infoPane, JLayeredPane.POPUP_LAYER);
                    if (landStore.checkSell()) {
                        setAllowed(true);
                        nextCard();
                        SwingWorker worker = new SwingWorker() {
                            @Override
                            protected Object doInBackground() throws Exception {
                                landStore.mainFunction();
                                return null;
                            }
                        };
                        worker.execute();
                        landStore.sell();
                        landStore.setCalculated(true);
                        updateInfoPanel();
                    }
                    setlandPhase(false);
                    sellPhase = false;

                    /* Player Sells Land */
                } else {
                    if (getCurrent().hasProperty()) {
                        sellPhase = true;
                        mainPane.add(infoPane, JLayeredPane.POPUP_LAYER);
                        nextCard();
                        sworker.execute();
                        getCurrent().addMoney(
                                GameConstants.DEFAULT_PROPETY_SELL_VALUE
                                + rand.nextInt(201));
                        lastClickedProperty.removeMule();
                    } else {
                        JOptionPane
                        .showMessageDialog(mainPane,
                                "Sorry! You don't have any properties to sell!");
                    }
                }

                /* Pub Button Clicked */
            } else if (location.equals("Pub")) {
                System.out.println("Pub Clicked!");
                int moneyBonus = pub.calcBonus(getCurrent().getRound(),
                        getCurrent().getTimeLeft());
                pub.addMoney(getCurrent(), moneyBonus);
                getCurrent().setTimer(getCurrent().roundLimit());
                updateInfoPanel();
                pubClicked = pub.endTurn();
                nextCard();
            } else if (location.equals("FoodStore")) {
                Object[] options = { "Sell", "Buy" };
                int n = JOptionPane
                        .showOptionDialog(storePane,
                                "Would like to buy or sell?", "FoodStore",
                                JOptionPane.YES_NO_CANCEL_OPTION,
                                JOptionPane.QUESTION_MESSAGE, null, options,
                                options[1]);
                if (n == 1) {
                    if (store.sellFood()[0]) {
                        purchaseSuccess(store.getPlayerName(), "food");
                    } else {
                        if (store.sellFood()[1]) {
                            notEnoughMoneyMessage();
                        }
                        itemNotAvailable("food");
                    }
                } else {
                    System.out.println("Selling Food!");
                    store.buyFood();
                }

                /* EnergyStore Button Clicked */
            } else if (location.equals("EnergyStore")) {
                Object[] options = { "Sell", "Buy" };
                int n = JOptionPane
                        .showOptionDialog(storePane,
                                "Would like to buy or sell?", "EnergyStore",
                                JOptionPane.YES_NO_CANCEL_OPTION,
                                JOptionPane.QUESTION_MESSAGE, null, options,
                                options[1]);
                if (n == 1) {
                    if (store.sellEnergy()[0]) {
                        purchaseSuccess(store.getPlayerName(), "energy");
                    } else {
                        if (store.sellEnergy()[1]) {
                            notEnoughMoneyMessage();
                        }
                        itemNotAvailable("energy");
                    }
                } else {
                    System.out.println("Selling Energy!");
                    store.buyEnergy();
                }

                /* Smith Store Button Pressed */
            } else if (location.equals("SmithStore")) {
                Object[] options = { "Sell", "Buy" };
                int n = JOptionPane
                        .showOptionDialog(storePane,
                                "Would like to buy or sell?", "SmithStore",
                                JOptionPane.YES_NO_CANCEL_OPTION,
                                JOptionPane.QUESTION_MESSAGE, null, options,
                                options[1]);
                if (n == 1) {
                    if (store.sellOre()[0]) {
                        // Ore purchased
                        purchaseSuccess(store.getPlayerName(), "smithore");
                    } else {
                        if (store.sellOre()[1]) {
                            // Player does not have enough money
                            notEnoughMoneyMessage();
                        }
                        itemNotAvailable("smithore");
                    }
                } else {
                    System.out.println("Selling Ore!");
                    store.buyOre();
                }
            }

            /* Mule Store Button Pressed */
            else if (location.equals("MULEStore")) {
                proceed = true;
                mulePhase = true;
                Object[] options = { "Food", "Ore", "Energy" };
                int n = JOptionPane
                        .showOptionDialog(storePane,
                                "Pick the type of mule you would like ",
                                "MULEStore", JOptionPane.YES_NO_CANCEL_OPTION,
                                JOptionPane.QUESTION_MESSAGE, null, options,
                                options[2]);
                if (!getCurrent().hasProperty()) {
                    JOptionPane
                    .showMessageDialog(mainPane,
                            "Sorry! You don't have any property to put a MULE on.");
                    proceed = false;

                    /* Energy Mule */
                } else if (n == 2) {
                    if (store.sellMule("Energy", lastClickedProperty)[0]) {
                        purchaseSuccess(store.getPlayerName(), "Energy MULE");
                        getCurrent().buying(GameConstants.ENERGY_MULE_PRICE);
                    } else {
                        if (store.sellMule("Energy", lastClickedProperty)[1]) {
                            notEnoughMoneyMessage();
                        }
                        itemNotAvailable("Energy MULE");
                    }
                }

                /* Ore Mule */
                else if (n == 1) {
                    if (store.sellMule("Ore", lastClickedProperty)[0]) {
                        purchaseSuccess(store.getPlayerName(), "Ore MULE");
                        getCurrent().buying(GameConstants.ORE_MULE_PRICE);
                    } else {
                        if (store.sellMule("Ore", lastClickedProperty)[1]) {
                            notEnoughMoneyMessage();
                        }
                        itemNotAvailable("Ore MULE");
                    }
                }

                /* Food Mule */
                else if (n == 0) {
                    if (store.sellMule("Food", lastClickedProperty)[0]) {
                        purchaseSuccess(store.getPlayerName(), "Food MULE");
                        getCurrent().buying(GameConstants.FOOD_MULE_PRICE);
                    } else {
                        if (store.sellMule("Food", lastClickedProperty)[1]) {
                            // Player does not have enough money
                            notEnoughMoneyMessage();
                        }
                        itemNotAvailable("Food MULE");
                    }
                }

                /* Proceed with mule check out */
                if (proceed) {
                    mainPane.add(infoPane, JLayeredPane.POPUP_LAYER);
                    if (store.checkMuleSold()) {
                        nextCard();
                        focusPane();
                        mworker.execute();
                        updateInfoPanel();
                    }
                    store.setMuleSold(false);
                }
            }
            mulePhase = false;
            updateInfoPanel();
        }
    }

    /*
     * ActionListener for Turn Passing
     */
    private class EnterListener implements KeyListener {
        /**
         * sets true if the user hits enter, effectively passing their turn for
         * this round
         */
        public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                passedEnter = true;
            }
        }

        @Override
        public void keyReleased(KeyEvent arg0) {
            /* Not Necessary */
        }

        @Override
        public void keyTyped(KeyEvent arg0) {
            /* Not Necessary */
        }
    }

    /*
     * Alternate ActionListener for Turn Passing
     */
    private class EnterAction extends AbstractAction {
        @Override
        /**
         * sets true if the user hits enter, effectively passing their turn for this round
         */
        public void actionPerformed(ActionEvent e) {
            passedEnter = true;

        }
    }

    /**
     * Return to GameMap when 'Back to Map' button is pressed
     */
    private class HomeListen implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            nextCard();

        }
    }

    /**
     * returns true if the pub was clicked
     * 
     * @return
     */
    public boolean getPubStatus() {
        return pubClicked;
    }

    /**
     * sets pubclicked boolean true
     */
    public void activatePub() {
        pubClicked = true;
    }

    /**
     * getter for the store
     * 
     * @return
     */
    public Store getStore() {
        return store;
    }

    /**
     * getter for the linkedlist of mules
     * 
     * @return
     */
    public LinkedList<IDAssociator> getMuleLabel() {
        return ownedMuleJLabels;
    }

    /**
     * returns the linkedlist of owned properties labels
     * 
     * @return
     */
    public LinkedList<IDAssociator> getownedPropLabel() {
        return ownedPropertiesJLabels;
    }

    /**
     * setter for the mule jlabels
     * 
     * @param imported
     */
    public void setMuleLabels(LinkedList<IDAssociator> imported) {
        ownedMuleJLabels = imported;
    }

    /**
     * setter for the property jlabels
     * 
     * @param imported
     */
    public void setPropLabels(LinkedList<IDAssociator> imported) {
        ownedPropertiesJLabels = imported;
    }

    /**
     * setter for the store
     * 
     * @param imported
     */
    public void setStore(Store imported) {
        store = imported;
    }

    /**
     * getter for the main GameScreen Panel
     * 
     * @return mainPane
     */
    public JLayeredPane getPane() {
        return mainPane;
    }

    /**
     * setter for the round number
     * 
     * @param num
     */
    public void setRoundNum(String num) {
        roundNum.setText(num);
    }

    /**
     * gets the chosen data from the board
     * 
     * @return chosen
     */
    public ArrayList<String> getChosenSave() {
        return chosen;
    }

    /**
     * sets the chosen properties data from the save file
     * 
     * @param data
     */
    public void setChosenData(ArrayList<String> data) {
        chosen = data;
    }
}
